package futbol.tacticas.concursantes.qualitycode.common;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import futbol.General;
import futbol.tacticas.concursantes.qualitycode.QCodeTactica;

public class QBall
{
  public static final int KICK_ABLE_SPEED = 14;
  public static final int KICK_RADIO = 10;
  public static final int DISTANCIA_MAXFUERZA = 50;
  
  private final Point prevPos = new Point(0,0);
  private List<QBall> futureBalls = null;
  private double x = QCodeTactica.INVALID;
  private double y = QCodeTactica.INVALID;
  private int speed = -1;
  private double angle;
  
  public QBall()
  {}
  
  public QBall(QBall ball)
  {
    this.speed = ball.speed;
    this.angle = ball.angle;
    this.x = ball.x;
    this.y = ball.y;
  }
  
  public void reset()
  {
    prevPos.setLocation(0, 0);
    x = 0;
    y = 0;
    speed = 0;
    angle = 0;    
  }  
  
  public void updatePos(Point point)
  {    
    prevPos.setLocation(x,y);
    x = point.x;
    y = point.y;
    
    if (QUtils.isValid(prevPos))
    {
      speed = (int) QUtils.distance(prevPos, new Point((int)x,(int)y));
      angle = QUtils.angle(prevPos, new Point((int)x,(int)y));      
    }
    futureBalls = null;
  }
  
  public boolean canGolpearIgnorarSpeed(QPlayer player)
  {
    return General.getDistancia(player.getX(), player.getY(), x, y) < KICK_RADIO;
  }
  
  public boolean canGolpear(QPlayer player)
  {    
    return speed <= KICK_ABLE_SPEED && 
           General.getDistancia(player.getX(), player.getY(), x, y) < KICK_RADIO;
  }

  public boolean isKickAble()
  {
    return speed <= KICK_ABLE_SPEED;
  }
  
  public void golpearBola(QPlayer player, double xDes, double yDes)
  {
    if (speed < 15)
    {
      int nGrado = 100;
      double dis = General.getDistancia(player.getX(), player.getY(), xDes, yDes);
      if (dis < DISTANCIA_MAXFUERZA)
        nGrado = (int) (dis * 2);
      
      final double fuerza = player.getForce();
      final int nFuerza = (int) (fuerza * nGrado / 100);
      
      angle = General.getAngulo(x, y, xDes, yDes);
      speed = nFuerza * 3;
      futureBalls = null;
    }
  }
  public void move()
  {
    for (int n = 0; n < speed && isGoal() == -1; n++)
    {
      x += Math.cos(angle);
      y += Math.sin(angle);
      
      if (isGoal() == -1)
      {
        if (x > 160)
        {
          x = 320 - x; // 160 - (x-160)
          angle = General.corregirAngulo(Math.PI - angle);
        }
        if (x < -160)
        {
          x = -320 - x; // -160 + (-160-x)
          angle = General.corregirAngulo(Math.PI - angle);
        }
        if (y > 120)
        {
          y = 240 - y; // 120 - (x-120)
          angle = General.corregirAngulo(-angle);
        }
        if (y < -120)
        {
          y = -240 - y; // -120 + (-120-x)
          angle = General.corregirAngulo(-angle);
        }
      }
    }
    
    if (speed > 0)
      speed--;
  }
  
  public int isGoal()
  {
    if (x >= 160 && y > -30 && y < 30)
      return 0;
    
    if (x <= -160 && y > -30 && y < 30)
      return 1;
    
    return -1;
  }

  public int getSpeed()
  {
    return speed;
  }
  
  public boolean isSpeedValid()
  {
    return speed >= 0;
  }
  
  public double getAngle()
  {
    return angle;
  }
  
  public Point getPos()
  {
    return new Point((int)x,(int)y);
  }
  
  /**
   * Retorna una lista de bolas, donde la primera bola es la bola actual y las siguientes
   * es la bola futura de la anterior asta llegar a velocidad 0
   * 
   * @return lista de bolas futuras. Si el tamana es 1 es porque la bola esta detenida.
   */
  public List<QBall> getFutureBalls()
  {
    if (futureBalls == null)
    {
      futureBalls = new ArrayList<QBall>();
      futureBalls.add(new QBall(this));
      
      if (getSpeed() > 0)
      {
        QBall futureBall = this;
        for(;futureBall.isGoal() == -1 && futureBall.getSpeed() > 0;)
        {
          futureBall = new QBall(futureBall);
          futureBall.move();
          futureBalls.add(futureBall);
        }
      }
      futureBalls = Collections.unmodifiableList(futureBalls);
      return futureBalls;
    }
    return futureBalls;
  }
  
  /**
   * Si la bola esta detenida siempre retorna la primer bola no importa si el indece es mayor
   * 
   * @param idx indice de la bola requerida
   * @return una bola, nunca null
   */
  public QBall getFutureBal(int idx)
  {
    if (futureBalls == null)
      getFutureBalls();
    
    if (idx >= futureBalls.size())
      return futureBalls.get(futureBalls.size()-1);
    else
      return futureBalls.get(idx);
  }

  public int getX()
  {
    return (int)x;
  }

  public int getY()
  {
    return (int) y;
  }

  public void pinar(boolean over, Graphics gdb)
  {
    if (!over)
      return;
      
    List<QBall> fBalls = futureBalls;
    if (fBalls != null && fBalls.size() > 1)
    {
      int blue = 50;
      Point p = getPos();
      for (int i = 1; i < fBalls.size(); i++)
      {
        final QBall ball = fBalls.get(i);
        if (ball.isKickAble())
        {
          int radio = (int) General.getDistancia(p.x, p.y, ball.x, ball.y);
          gdb.setColor(new Color(255,255,blue));
          
          gdb.drawOval(141+160-getX()-radio/2, 91+120-getY()-radio/2, radio, radio);
          blue += 6;
        }
        
        p = ball.getPos();
      }
    }
  }
  
}







